import asyncio

import pydantic
import sanic
from loguru import logger

from mnagent.manager import App

from .lib.common import get_host_info, get_host_ip4s


class K2CIAgentCFG(pydantic.BaseModel):
    smp_ip: str = "127.0.0.1"
    smp_port: int = 10001
    smp_register_uri: str = "/smp/device/register"
    smp_heartbeat_uri: str = "/smp/device/heartbeat"

    rabbit_mq_ip: str = "127.0.0.1"
    rabbit_port: int = 5672
    rabbit_username: str = "admin"
    rabbit_passwd: str = "admin123$"
    rabbit_msg_exchange: str = "k2ci_agent_exchange"
    rabbit_msg_queue: str = "k2ci_agent_queue"
    rabbit_ignore_max_retry: bool = False
    rabbit_ignore_conn_error: bool = True


class K2CIAgent:
    def __init__(self, cfg_path: str):
        self.app = App.create(cfg_path)
        self.cfg = K2CIAgentCFG.model_validate(self.app.agent.cfg.base.user_config)
        self.host_info = get_host_info()
        self.ip4_info = get_host_ip4s()

        from .lib.smp import SMP
        self.smp = SMP(self)
        from .lib.rabbit_mq import RabbitMQClient
        self.mq_client = RabbitMQClient(self)

        @self.app.manger.before_server_start
        async def before_start(app: sanic.Sanic):
            logger.info(f"[K2CI] 本机地址：{self.ip4_info}")
            # 首次注册
            await self._register()

            logger.info("[K2CI] 添加注册任务")
            self.app.agent.task_scheduler.scheduler.add_job(
                self._register,
                trigger="interval",
                seconds=120
            )

            logger.info("[K2CI] 添加心跳任务")
            self.app.agent.task_scheduler.scheduler.add_job(
                self.smp.is_keep_alive,
                trigger="interval",
                seconds=60
            )

        @self.app.manger.after_server_stop
        async def after_stop(app: sanic.Sanic):
            await self.mq_client.close()
            await self.smp.unregister()

    async def _register(self):
        await self.mq_client.try_connect(
            ignore_max_retry=self.cfg.rabbit_ignore_max_retry,
            ignore_conn_error=self.cfg.rabbit_ignore_conn_error
        )
        await self.smp.register()

    def run(self):
        self.app.run()
